#include "Digest.hpp"

using namespace BFT::messages;

Digest::Digest()
{
	bytes.reset( (char*)malloc(sizeof(char)*DIGEST_SIZE), free);
	memset( (void*)bytes.get(), 255, sizeof(char)*DIGEST_SIZE);
	//bytes.get()[0]= 65;
	//bytes.get()[DIGEST_SIZE]=65;
	count=0;
}

Digest::Digest(boost::shared_ptr<char> _bytes, uint32_t _bytes_length)
{
	//Digest(_bytes, _bytes_length, (uint32_t)0);
	bytes.reset( (char*)malloc(sizeof(char)*DIGEST_SIZE), free);
	memset( (void*)bytes.get(), 255, sizeof(char)*DIGEST_SIZE);
	//bytes.get()[0]= 65;
	//bytes.get()[DIGEST_SIZE]=65;
	count=0;
	
	//at this point I am generating a fake digest
	
//	*(uint32_t*)bytes.get() = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+4) = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+8) = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+12) = htonl((uint32_t)3735928559); //DEADBEEF

}

Digest::Digest(boost::shared_ptr<char> _bytes, uint32_t _bytes_length, uint32_t _offset)
{
	//pfrintf(stderr, "******** constructing Digest, offset: %d\n",_offset);
	
	//Digest();
	
	bytes.reset( (char*)malloc(sizeof(char)*DIGEST_SIZE), free);
	memset( (void*)bytes.get(), 255, sizeof(char)*DIGEST_SIZE);
	//bytes.get()[0]= 65;
	//bytes.get()[DIGEST_SIZE]=65;
	count=0;
	
	//at this point I am generating a fake digest
	
//	*(uint32_t*)bytes.get() = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+4) = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+8) = htonl((uint32_t)3735928559); //DEADBEEF
//	*(uint32_t*)(bytes.get()+12) = htonl((uint32_t)3735928559); //DEADBEEF
	
	/*
	//generating a real digest using MD5 (openssl implementation)
	EVP_MD_CTX mdctx;
	const EVP_MD *md;
	md = EVP_get_digestbyname("md5");
	EVP_MD_CTX_init(&mdctx);
	EVP_DigestInit_ex(&mdctx, md, NULL);
	EVP_DigestUpdate(&mdctx, _bytes.get()+ _offset, _bytes_length - _offset);
	unsigned int digest_size;
	EVP_DigestFinal(&mdctx, (unsigned char*)bytes.get(), &digest_size);
	if (digest_size!=DIGEST_SIZE)
	{
		fprintf(stderr, "expected digest size: %d, real digest size: %d\n",DIGEST_SIZE, digest_size);
		exit(66);
	}
	*/
}

boost::shared_ptr<Digest> Digest::fromBytes(boost::shared_ptr<char> _bytes, uint32_t _bytes_length)
{
	if(_bytes_length != DIGEST_SIZE)
	{
		fprintf(stderr,"something wrong in the generation of the Digest starting from bytes (wrong size of bytes)\n");
		exit(10);
	}
	boost::shared_ptr<Digest> d (new Digest());
	//memcpy( (void*)d.get()->bytes, (const void*)_bytes, sizeof(char)*DIGEST_SIZE);
	d.get()->setBytes(_bytes);
	return d;
}

uint32_t Digest::size()
{
	return DIGEST_SIZE;
}

bool Digest::equals(boost::shared_ptr<Digest> _d)
{
	if (_d.use_count()==0)
		return false;
	bool different=false;
	
	boost::shared_ptr<char> other_bytes = _d.get()->getBytes();
	
	for (int i=0; i<DIGEST_SIZE; i++)
	{
		different = different || ( bytes.get()[i] != other_bytes.get()[i] ); 

	}
	if (different)	
		return false;		
	return true; 
}

void Digest::setBytes(boost::shared_ptr<char> _bytes)
{
	memcpy((void*)bytes.get(), (void*)_bytes.get(), DIGEST_SIZE);
}

void Digest::printInfo()
{
	if(bytes.use_count() == 0)
	{
		fprintf(stderr,"nothing to print information about...\n");
	}
	else
	{
		for (int i=0; i< DIGEST_SIZE; i++)
			fprintf(stdout,"|%02X",(unsigned char)bytes.get()[i]);
		fprintf(stdout,"\n");
	}
}

/*
void Digest::computeDigest(boost::shared_ptr<char> _bytes, uint32_t _bytes_length)
{
	computeDigest( _bytes, _bytes_length, 0);
}
			
void Digest::computeDigest(boost::shared_ptr<char> _bytes, uint32_t _bytes_length, uint32_t offset)
{
}
*/
